package cn.easyutil.project.service.mybatis;

import cn.easyutil.project.base.sqlExecuter.annotation.TableField;
import cn.easyutil.util.javaUtil.JsonUtil;
import cn.easyutil.util.javaUtil.ObjectUtil;
import cn.easyutil.util.javaUtil.StringUtil;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.mapping.ResultMapping;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.util.*;
import java.util.Map.Entry;


/**
 * mybatis返回拦截器
 * @author spc
 *
 */
//@Component
@Intercepts({ @Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class,
        RowBounds.class, ResultHandler.class }) })
public class MybatisResultInterceptor implements Interceptor{
	
	private static final List<ResultMapping> EMPTY_RESULTMAPPING = new ArrayList<ResultMapping>(
			0);

	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		final Object[] args = invocation.getArgs();
		MappedStatement ms = (MappedStatement) args[0];
		Class resultType = getReslutType(ms);
		if (resultType == null) {
			return invocation.proceed();
		}
		// 复制ms，重设类型
		args[0] = newMappedStatement(ms);

		Object value = invocation.proceed();
		if (value!=null && Collection.class.isAssignableFrom(value.getClass())) {
			return parseObject((List<Map>) value, resultType);
		}
		return value;
	}

	private Object parseObject(List<Map> value, Class resultType) {
		if(value==null || value.isEmpty()){
			return value;
		}
		if(value.size()==1 && value.get(0)==null){
			return value;
		}
		//获取java字段注解
		Map<String, TableField> map = ObjectUtil.getFieldAnnotation(resultType, TableField.class);
		List<Map> result = new ArrayList<>();
		Set<Entry<String, TableField>> entrySet = map.entrySet();
		for (Map m : value) {
			Map<String, Object> re = JsonUtil.jsonToMap(JsonUtil.beanToJson(m));

			result.add(re);
			Set<Entry<Object, Object>> set = m.entrySet();
			//将所有的数据库字段转换成驼峰添加到返回值里面
			for (Entry<Object, Object> entry : set) {
				Object key = entry.getKey();
				Object val = entry.getValue();
				String converKey = StringUtil.conversionCamelCase(key.toString());
//				m.put(converKey, val);
				re.put(converKey, val);
			}
			//无注解，不需要映射
			if(map==null || map.isEmpty()){
				continue;
			}
			//如果有tableField注解，则转换为注解配置中的java字段名
			for (Entry<String, TableField> entry : entrySet) {
				String javaField = entry.getKey();
				String sqlField = StringUtil.isEmpty(entry.getValue().value())?entry.getValue().name():entry.getValue().value();
				if(StringUtil.isEmpty(sqlField) || javaField.equals(sqlField)){
					continue;
				}
				//获取原返回值
				Object val = m.get(sqlField);
//				m.put(javaField, val);
//				m.remove(sqlField);
				re.put(javaField, val);
				re.remove(sqlField);
			}
		}
		return JsonUtil.jsonToList(JsonUtil.beanToJson(result), resultType);
	}

	@Override
	public Object plugin(Object target) {
		return Plugin.wrap(target, this);
	}

	@Override
	public void setProperties(Properties properties) {
	}

	private Class getReslutType(MappedStatement ms) {
		List<ResultMap> maps = ms.getResultMaps();
		ResultMap rm = maps != null && maps.size() > 0 ? maps.get(0) : null;
		if (rm != null) {
			Class classzz = rm.getType();
			if(ObjectUtil.isBaseClass(classzz)){
				return null;
			}
			return classzz;
		}
		return null;
	}
	
	/**
	 * 根据现有的 ms 创建一个新的，使用新的返回值类型
	 * 
	 * @param ms
	 * @return
	 */
	private MappedStatement newMappedStatement(MappedStatement ms) {
		Class mapClass = Map.class;

		// 下面是新建的过程，考虑效率和复用对象的情况下，这里最后生成的ms可以缓存起来，下次根据 ms.getId() + "_" +
		// getShortName(resultType) 直接返回 ms,省去反复创建的过程
		MappedStatement.Builder builder = new MappedStatement.Builder(
				ms.getConfiguration(), ms.getId(), ms.getSqlSource(),
				ms.getSqlCommandType());
		builder.resource(ms.getResource());
		builder.fetchSize(ms.getFetchSize());
		builder.statementType(ms.getStatementType());
		builder.keyGenerator(ms.getKeyGenerator());
		if (ms.getKeyProperties() != null && ms.getKeyProperties().length != 0) {
			StringBuilder keyProperties = new StringBuilder();
			for (String keyProperty : ms.getKeyProperties()) {
				keyProperties.append(keyProperty).append(",");
			}
			keyProperties.delete(keyProperties.length() - 1,
					keyProperties.length());
			builder.keyProperty(keyProperties.toString());
		}
		builder.timeout(ms.getTimeout());
		builder.parameterMap(ms.getParameterMap());
		// count查询返回值int
		List<ResultMap> resultMaps = new ArrayList<ResultMap>();
		ResultMap resultMap = new ResultMap.Builder(ms.getConfiguration(),
				ms.getId(), mapClass, EMPTY_RESULTMAPPING).build();
		resultMaps.add(resultMap);
		builder.resultMaps(resultMaps);
		builder.resultSetType(ms.getResultSetType());
		builder.cache(ms.getCache());
		builder.flushCacheRequired(ms.isFlushCacheRequired());
		builder.useCache(ms.isUseCache());
		return builder.build();
	}
}
